using System;

namespace NFreeMarker.Template.Utility
{
    public abstract class Number // TODO: Should be internal
    {
        public abstract byte ByteValue();

        public abstract decimal DecimalValue();

        public abstract double DoubleValue();

        public abstract float FloatValue();

        public abstract int IntValue();

        public abstract long LongValue();

        public abstract sbyte SByteValue();

        public abstract short ShortValue();

        public abstract uint UIntValue();

        public abstract ulong ULongValue();

        public abstract ushort UShortValue();

        internal class NumberBase<T> : Number
        {
            private readonly T _value;

            protected NumberBase(T value)
            {
                _value = value;
            }

            public override byte ByteValue()
            {
                return Convert.ToByte(_value);
            }

            public override decimal DecimalValue()
            {
                return Convert.ToDecimal(_value);
            }

            public override double DoubleValue()
            {
                return Convert.ToDouble(_value);
            }

            public override float FloatValue()
            {
                return Convert.ToSingle(_value);
            }

            public override int IntValue()
            {
                return Convert.ToInt32(_value);
            }

            public override long LongValue()
            {
                return Convert.ToInt64(_value);
            }

            public override sbyte SByteValue()
            {
                return Convert.ToSByte(_value);
            }

            public override short ShortValue()
            {
                return Convert.ToInt16(_value);
            }

            public override uint UIntValue()
            {
                return Convert.ToUInt32(_value);
            }

            public override ulong ULongValue()
            {
                return Convert.ToUInt64(_value);
            }

            public override ushort UShortValue()
            {
                return Convert.ToUInt16(_value);
            }

            public override string ToString()
            {
                return _value.ToString();
            }
        }

        internal class ByteNumber : NumberBase<byte>
        {
            public ByteNumber(byte value) : base(value)
            {
            }
        }

        internal class DecimalNumber : NumberBase<decimal>
        {
            public DecimalNumber(decimal value) : base(value)
            {
            }
        }

        internal class DoubleNumber : NumberBase<double>
        {
            public DoubleNumber(double value) : base(value)
            {
            }
        }

        internal class FloatNumber : NumberBase<float>
        {
            public FloatNumber(float value) : base(value)
            {
            }
        }

        internal class IntNumber : NumberBase<int>
        {
            public IntNumber(int value) : base(value)
            {
            }
        }

        internal class LongNumber : NumberBase<long>
        {
            public LongNumber(long value) : base(value)
            {
            }
        }

        internal class SByteNumber : NumberBase<sbyte>
        {
            public SByteNumber(sbyte value) : base(value)
            {
            }
        }

        internal class ShortNumber : NumberBase<short>
        {
            public ShortNumber(short value) : base(value)
            {
            }
        }

        internal class UIntNumber : NumberBase<uint>
        {
            public UIntNumber(uint value) : base(value)
            {
            }
        }

        internal class ULongNumber : NumberBase<ulong>
        {
            public ULongNumber(ulong value) : base(value)
            {
            }
        }

        internal class UShortNumber : NumberBase<ushort>
        {
            public UShortNumber(ushort value) : base(value)
            {
            }
        }
    }
}